package io.itit.ecp.admin.provide.action.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IPhysicalModelModelFutureEnums;
import io.itit.ecp.admin.provide.action.req.DeviceQueryReq;
import io.itit.ecp.admin.provide.action.req.DeviceReq;
import io.itit.ecp.admin.provide.action.req.MeterDeviceRunningParamReq;
import io.itit.ecp.admin.provide.action.resp.DeviceResp;
import io.itit.ecp.admin.provide.action.resp.PhysicalModelResp;
import io.itit.ecp.admin.provide.filter.IDeviceFilter;
import io.itit.ecp.admin.provide.helper.SceneHelper;
import io.itit.ecp.admin.provide.renderer.DeviceRenderer;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.entity.extend.PhysicalModelExt;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.entity.BaseEntity;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * <p>
 *
 * @Author：Roy
 * @Description：设备管理控制类
 * @Date：Create by 2023-11-30 18:51:39
 */
@Api(tags = "设备管理")
@RestController
@RequestMapping("/ecp-admin/device")
public class DeviceController {

    @Resource
    private IDeviceService deviceService;

    @Resource
    private ISceneRoomService sceneRoomService;

    @Resource
    private IProductTypeService productTypeService;

    @Resource
    private IPhysicalModelService physicalModelService;

    @Resource
    private IDeviceRunningHistoryService deviceRunningHistoryService;

    @Resource
    private IDeviceRunningValueService deviceRunningValueService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:device:search")
    public ResultResp<IPage<DeviceResp>> queryPage(@RequestBody @Validated(IQueryPage.class) DeviceQueryReq req) {
        Page<DeviceResp> page = new Page<>();
        if (req.getSenceCompanyId() != null) {
            ArrayList<DeviceResp> listTotalDevice = new ArrayList<>();//所有设备
            List<SceneRoomEntity> rooms = sceneRoomService.lambdaQuery()//公司所对应的空间
                    .eq(StringUtils.isNotEmpty(req.getSenceCompanyId()), SceneRoomEntity::getSceneCompanyId, req.getSenceCompanyId())
                    .list();
            for (SceneRoomEntity room : rooms) {//遍历所有空间
                req.setSceneRoomId(room.getId());//赋值给req
                List<DeviceResp> records = buildQW(req).joinList(DeviceResp.class);//得到的room所对应的设备
                listTotalDevice.addAll(records);
            }
            page.setRecords(listTotalDevice);

            return ResultResp.success(SceneHelper.i().setSceneInfo(page));
        }

        page = buildQW(req).joinPage(PageUtils.getPage(req, DeviceResp.class), DeviceResp.class);
        return ResultResp.success(SceneHelper.i().setSceneInfo(page));
    }

    @ApiOperation("获取物联网设备状态")
    @GetMapping("getDeviceStatus")
    @RequiresPermissions("ecp-admin:device:search")
    public ResultResp<String> detail(@RequestParam String deviceCode) {
        return ResultResp.success("1"); // 1:在线， 2：离线
    }

    /**
     * 保存运行参数
     */
    @ApiOperation("运行参数保存")
    @PostMapping("saverunningparameter")
    @Transactional
    @RequiresPermissions("ecp-admin:device:update")
    public ResultResp<Boolean> saveRunningParameter(@RequestBody MeterDeviceRunningParamReq req) {
        Set<String> modelIds = req.getRunningParams().stream()
                .map(MeterDeviceRunningParamReq.RunningParam::getPhysicalModelId)
                .collect(Collectors.toSet());
        List<PhysicalModelEntity> physicalModelEntities = physicalModelService.listByIds(modelIds);
        List<DeviceRunningHistoryEntity> historyEntities = new ArrayList<>();
        for (PhysicalModelEntity modelEntity : physicalModelEntities) {
            String modelFeatures = modelEntity.getModelFeatures();
            String dataType = modelEntity.getDataType();
            MeterDeviceRunningParamReq.RunningParam runningParam = req.getRunningParams()
                    .stream()
                    .filter(item -> StringUtils.equals(modelEntity.getId(), item.getPhysicalModelId()))
                    .findFirst()
                    .get();
//            if (IPhysicalModelModelDataTypeEnums.FIXED.getValue().equals(dataType)) { //静态数据 , //TODO: 先所有数据都保存
            // 静态数据保存
            DeviceRunningValueEntity runningValueEntity = deviceRunningValueService.findByDeviceIdAndPhysicalModelId(req.getDeviceId(), runningParam.getPhysicalModelId())
                    .orElse(new DeviceRunningValueEntity()
                            .setDeviceId(req.getDeviceId())
                            .setPhysicalModelId(runningParam.getPhysicalModelId()));
            runningValueEntity.setRunningValue(runningParam.getRunningValue());
            deviceRunningValueService.saveOrUpdate(runningValueEntity);
//            } else {
//                deviceRunningValueService.removeByDeviceIdAndPhysicalModelId(req.getDeviceId(), runningParam.getPhysicalModelId());
//            }
            if (StringUtils.isNotEmpty(modelFeatures)) {
                String[] modelFeatureArr = modelFeatures.split(",");
                for (String modelFeature : modelFeatureArr) {
                    IPhysicalModelModelFutureEnums modelFutureEnums = IPhysicalModelModelFutureEnums.getByValue(modelFeature);
                    switch (modelFutureEnums) {
                        case REALTIME_MONITOR:
                        case READONLY_DATA:
                        case MEASUREMENT_PARAMETERS:
                            break;
                        case HISTORY_STORAGE:
                            historyEntities.add(new DeviceRunningHistoryEntity()
                                    .setDeviceId(req.getDeviceId())
                                    .setPhysicalModelId(modelEntity.getId())
                                    .setRunningValue(req.getRunningParams().stream()
                                            .filter(item -> StringUtils.equals(item.getPhysicalModelId(), modelEntity.getId())).findFirst()
                                            .map(MeterDeviceRunningParamReq.RunningParam::getRunningValue).orElse(null))
                            );
                            break;
                    }
                }
            }
        }
        deviceRunningHistoryService.saveBatch(historyEntities);
        return ResultResp.success(true);
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    public ResultResp<DeviceResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        return ResultResp.success(ConvertUtils.copy(deviceService.getById(req.getId()), DeviceResp.class));
    }

    @ApiOperation("查询设备关联产品关联的模型信息")
    @PostMapping("modellist")
    @RequiresPermissions(value = {"ecp-admin:device:search", "ecp-admin:deviceWarning:add", "ecp-admin:deviceWarning:update"}, logical = Logical.OR)
    public ResultResp<List<PhysicalModelResp>> modelList(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        List<PhysicalModelExt> physicalModelExts = deviceService.queryModelByDeviceId(req.getId());
        return ResultResp.success(ConvertUtils.convert(physicalModelExts, PhysicalModelResp.class));
    }

    /**
     * 检查设备是否存在
     */
    @GetMapping("exist")
    @RequiresPermissions("ecp-admin:device:search")
    public ResultResp<Boolean> exists(DeviceQueryReq req) {
        Set<String> roomIdList = new HashSet<>();
        if (StringUtils.isNotEmpty(req.getSenceCompanyId())) {
            roomIdList.addAll(sceneRoomService.lambdaQuery()//公司所对应的空间
                    .eq(StringUtils.isNotEmpty(req.getSenceCompanyId()), SceneRoomEntity::getSceneCompanyId, req.getSenceCompanyId())
                    .list().stream().map(BaseEntity::getId).collect(Collectors.toSet()));
        }
        if (StringUtils.isNotEmpty(req.getSceneRoomId())) {
            roomIdList.add(req.getSceneRoomId());
        }
        return ResultResp.success(deviceService.exists(new LambdaQueryWrapper<DeviceEntity>()
                .eq(StringUtils.isNotBlank(req.getSceneProjectId()), DeviceEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.isNotBlank(req.getSceneEdificeId()), DeviceEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.isNotBlank(req.getSceneFloorId()), DeviceEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.isNotBlank(req.getProductTypeId()), DeviceEntity::getProductTypeId, req.getProductTypeId())
                .in(CollectionUtils.isNotEmpty(roomIdList), DeviceEntity::getSceneRoomId, roomIdList)
        ));
    }

    /**
     * 组装查询条件
     */
    private static JoinLambdaWrapper<DeviceEntity> buildQW(DeviceQueryReq req) {
        return Joins.of(DeviceEntity.class)
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, DeviceEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(ProductTypeEntity.class, ProductTypeEntity::getId, DeviceEntity::getProductTypeId)
                .select(ProductTypeEntity::getProductTypeName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getDeviceCode()), DeviceEntity::getDeviceCode, req.getDeviceCode())
                .eq(StringUtils.isNotEmpty(req.getDeviceName()), DeviceEntity::getDeviceName, req.getDeviceName())
                .eq(StringUtils.isNotEmpty(req.getDeviceType()), DeviceEntity::getDeviceType, req.getDeviceType())
                .in(CollectionUtils.isNotEmpty(req.getDeviceTypeList()), DeviceEntity::getDeviceType, req.getDeviceTypeList())
                .eq(StringUtils.isNotEmpty(req.getIsFocus()), DeviceEntity::getIsFocus, req.getIsFocus())
                .eq(StringUtils.isNotEmpty(req.getProductTypeId()), DeviceEntity::getProductTypeId, req.getProductTypeId())
                .eq(StringUtils.isNotEmpty(req.getDeviceStatus()), DeviceEntity::getDeviceStatus, req.getDeviceStatus())
                .in(CollectionUtils.isNotEmpty(req.getDeviceStatusList()), DeviceEntity::getDeviceStatus, req.getDeviceStatusList())
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), DeviceEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.isNotEmpty(req.getSceneEdificeId()), DeviceEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.isNotEmpty(req.getSceneFloorId()), DeviceEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.isNotEmpty(req.getSceneRoomId()), DeviceEntity::getSceneRoomId, req.getSceneRoomId())
                .eq(StringUtils.isNotEmpty(req.getPosition()), DeviceEntity::getPosition, req.getPosition())
                .eq(StringUtils.isNotEmpty(req.getRemark()), DeviceEntity::getRemark, req.getRemark())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), DeviceEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), DeviceEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByDesc(StringUtils.isEmpty(req.getSortColumn()), DeviceEntity::getCreateTm);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:device:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) DeviceReq req) {
        checkDataExists(req);
        return ResultResp.success(deviceService.save(ConvertUtils.convertIgnoreId(req, DeviceEntity.class)));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:device:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) DeviceReq req) {
        checkDataExists(req);
        return ResultResp.success(deviceService.updateById(ConvertUtils.copy(req, DeviceEntity.class)));
    }

    private void checkDataExists(DeviceReq req) {
        Long count = deviceService.lambdaQuery()
                .eq(DeviceEntity::getDeviceCode, req.getDeviceCode())
                .ne(StringUtils.isNotEmpty(req.getId()), DeviceEntity::getId, req.getId())
                .count();
        GrassException.throwEx(count > 0, "设备编码已存在！");
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:device:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(deviceService.removeById(req.getId()));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:device:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(deviceService.removeBatchByIds(req.getIds(), 1000));
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:device:upload")
    public ResultResp<Integer> upload(@RequestParam("file") MultipartFile file, Boolean ignoreError) {
        return ResultResp.success(ExcelParseManage.i().process(DeviceRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:device:export")
    public void export(@RequestBody @Validated(IExport.class) DeviceQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("DeviceExport", JsonUtil.toJson(deviceService.list(buildQW(req)), new IDeviceFilter.DeviceExportFilter()), response);
    }
}
